/*
 * Copyright (C) 2010 M. Hautle.
 * 
 * This file is part of TrackedBean.
 * 
 * TrackedBean is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * TrackedBean is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with TrackedBean. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.trackedbean.tracking;

import java.beans.*;
import java.util.*;
import ch.simpleel.*;
import ch.trackedbean.tracking.internal.*;

/**
 * Utility class for {@link TrackedBean}s.
 * 
 * @author M. Hautle
 */
public class TrackedBeanUtils {
    /**
     * Hidden constructor.
     */
    private TrackedBeanUtils() {
    }

    /**
     * Returns the {@link IBeanStatus} of a bean
     * 
     * @param <T> The bean type
     * @param bean The bean or null
     * @return The beanstatus or null if there is none
     */
    @SuppressWarnings("unchecked")
    public static <T> IBeanStatus<T> getBeanStatus(final T bean) {
        if (bean instanceof StatusInformationInternal)
            return ((StatusInformationInternal) bean)._getBeanStatus();
        return null;
    }

    /**
     * Resets the status information of the given bean.<br>
     * Use this method after initializing a Bean.
     * 
     * @param bean The bean
     */
    public static void resetBeanStatus(final Object bean) {
        if (bean instanceof StatusInformationInternal)
            getBeanStatus(bean).clearInitialValues(true);
    }

    /**
     * Resets the status information of the given list.<br>
     * Use this method after initializing a tracked list.
     * 
     * @param list The list
     */
    public static void resetListStatus(final List list) {
        if (list instanceof StatusList)
            ((StatusList) list).resetStatus();
    }

    /**
     * Resets the properties of the given bean to their initial value.
     * 
     * @param bean The bean
     * @throws ResetException If something went wrong
     */
    public static void resetToInitialValues(final Object bean) throws ResetException {
        if (bean instanceof StatusInformationInternal)
            getBeanStatus(bean).resetToInitialValues();
    }

    /**
     * Returns the {@link IBeanStatus} of a nested Bean
     * 
     * @param bean The base bean
     * @param path The path to a Bean relative to the basebean
     * @return The {@link IBeanStatus} of the bean at the end of the given path or null if there is none
     */
    public static IBeanStatus getBeanStatus(Object bean, final String path) {
        if (path.length() > 0)
            bean = ValueAccessorManager.getValueOf(path, bean, null);
        return getBeanStatus(bean);
    }

    /**
     * Returns the status of the property at the end of the given path
     * 
     * @param bean The base bean
     * @param path The path to the property in which status your interested in
     * @return The status of the property or null
     */
    public static Status getPropertyStatus(final Object bean, final String path) {
        try {
            final int lastIndex = path.lastIndexOf('.');
            return getBeanStatus(bean, lastIndex > 0 ? path.substring(0, lastIndex) : "").getStatus(path.substring(lastIndex + 1));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Adds the given {@link PropertyChangeListener} to the bean.<br>
     * This method works only for {@link TrackedBean} like objects.
     * 
     * @param bean The bean were to add the listener
     * @param l The listener to add
     * @return True if the listener add method was called (so false if the passed bean is not {@link TrackedBean} 'compatible')
     */
    public static boolean addPropertyChangeListener(Object bean, PropertyChangeListener l) {
        if (bean instanceof StatusInformationInternal) {
            ((StatusInformationInternal) bean).addPropertyChangeListener(l);
            return true;
        }
        return false;
    }

    /**
     * Removes the given {@link PropertyChangeListener} from the bean.<br>
     * This method works only for {@link TrackedBean} like objects.
     * 
     * @param bean The bean were to remove the listener
     * @param l The listener to remove
     * @return True if the listener removal method was called (so false if the passed bean is not {@link TrackedBean} 'compatible')
     */
    public static boolean removePropertyChangeListener(Object bean, PropertyChangeListener l) {
        if (bean instanceof StatusInformationInternal) {
            ((StatusInformationInternal) bean).removePropertyChangeListener(l);
            return true;
        }
        return false;
    }
}
